/* app_lwip_tcp_client_loop.c */

#include "app_inc.h"

/*******************************************************************************
 * Definitions
 ******************************************************************************/

/*******************************************************************************
 * Variables
 ******************************************************************************/

/*******************************************************************************
 * Prototypes
 ******************************************************************************/
static err_t app_lwip_tcp_client_connect(void *arg, struct tcp_pcb *tpcb, err_t err);
static err_t app_lwip_tcp_client_poll(void *arg, struct tcp_pcb *tpcb);
static err_t app_lwip_tcp_client_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err);

/*******************************************************************************
 * Code
 ******************************************************************************/
/* 客户端线程初始化完成后, 连上特定的服务器端口, 并周期发送字符串. */
void app_lwip_tcp_client_init(void)
{
    printf("[Client] connecting remote tcp server: 192.168.1.103:6060 ...\r\n");

    struct tcp_pcb * pcb = tcp_new();

    /* 设置目标服务器地址为环回地址 */
    struct ip_addr ipaddr;
    IP4_ADDR(&ipaddr, 192, 168, 1, 103);

    /* 连接服务器的6060端口, 并且注册连接函数.
     * 一旦客户端连接成功, 将由lwip自动调用app_lwip_tcp_client_loop_connect()函数. */
    tcp_connect(pcb, &ipaddr, 6060, app_lwip_tcp_client_connect);
    printf("[Client] tcp_connect() done.\r\n");
}

/* 连接成功后, lwip自动调用本函数.
 * 本函数先处理环回接口收数任务, 在执行发数操作.
 * 在第一次调用本函数时, 收到数据长度为0, 但是发送一组数; 下次收到的数就是本次发送的数.
 */
static err_t app_lwip_tcp_client_connect(void *arg, struct tcp_pcb *tpcb, err_t err)
{
    tcp_recv(tpcb, app_lwip_tcp_client_recv);
    tcp_poll(tpcb, app_lwip_tcp_client_poll, 10); /* 10个tcp定时周期 = 5秒. */
    return ERR_OK;
}

/* tcp client 接收tcp数据包 */
static err_t app_lwip_tcp_client_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
{
    if (p != NULL)
    {

        /* 提取tcp server发来的tcp包. */
        char * data_recv = (char *)mem_calloc(p->tot_len + 1, 1); /* 多的1个字节存放的是'\0', 作为字符串的结尾符. */
        if (NULL == data_recv)
        {
            printf("[Client] mem_calloc error, len = %u\r\n", p->tot_len);
        }
        else
        {
            /* 把pbuf链中的数据内容复制到一块连续的内存区中. */
            struct pbuf * q = p;
            int index = 0;

            while(q != NULL)
            {
                memcpy(&data_recv[index],q->payload,q->len);
                index += q->len;
                q = q->next;
            }

            /* 再次插入用户程序在tcp server收到数据有的处理过程. */
            printf("[Client] Get MSG: %s\r\n", data_recv);

            /* 释放内存空间 */
            mem_free(data_recv);
            data_recv = NULL;
        }

        tcp_recved(pcb, p->tot_len);
        pbuf_free(p);
    }
    else if (err == ERR_OK)
    {
        return tcp_close(pcb);
    }

    return ERR_OK;
}

/* tcp client 发送tcp数据包. */
static err_t app_lwip_tcp_client_poll(void *arg, struct tcp_pcb *tpcb)
{
    static unsigned int count = 0;
    char msg[32] = {0,};
    int len = sprintf(msg, "enc28j60_netif, count = %u\r\n", count++);

    /* 向tcp server发送tcp数据包. */
    tcp_write(tpcb, msg, len, TCP_WRITE_FLAG_COPY);
    return ERR_OK;
}

/* EOF. */

